#include "str.h"
#include "global_variables.h"
#include "useful_functions.h"

bool str::begins_with(const string &src, const string &search_string, bool case_sensitive) {
  if (src.length() < search_string.length())
    return false;

  if (case_sensitive == true)
    return (src.compare(0, search_string.length(), search_string) == 0);
  else
    return equal(search_string.begin(), search_string.end(), src.begin(), case_insensitive_char_compare);
}

bool str::ends_with(const string &src, const string &search_string, bool case_sensitive) {
  if (src.length() < search_string.length())
    return false;

  if (case_sensitive == true)
    return (src.compare(src.length() - search_string.length(), search_string.length(), search_string) == 0);

  string::const_iterator it = find_end(src.cbegin(), src.cend(), search_string.cbegin(), search_string.cend(), case_insensitive_char_compare);
  if (it == src.end())
    return false;
  else if (distance(it, src.end()) == search_string.length())
    return true;
  else
    return false;
}

bool str::contains(const string &src, const string &search_string, bool case_sensitive) {
  if (src.length() < search_string.length())
    return false;

  if (case_sensitive == true)
    return (src.find(search_string) != string::npos);
  else
    return (search(src.begin(), src.end(), search_string.begin(), search_string.end(), case_insensitive_char_compare) != src.end());
}

bool str::equals(const string &src, const string &search_string, bool case_sensitive) {
  if (case_sensitive == true)
    return (src == search_string);

  if (src.length() != search_string.length())
    return false;

  return equal(src.begin(), src.end(), search_string.begin(), case_insensitive_char_compare);
}

bool str::is_digit(const string &src) {
  return (find_if(src.begin(), src.end(), is_not_digit) == src.end());
}

void str::replace_all(string &src, const string &search_string, const string &replace_with) {
  string result;
  converter::replace_all(src, search_string, replace_with, result);
  src = result;
}

void str::remove_all(string &src, const string &search_string) {
  replace_all(src, search_string, global_empty_string);
}

void str::trim(string &src, const string &trim_characters) {
  converter::trim(src, trim_characters);
}

void str::trim_left(string &src, const string &trim_characters) {
  converter::trim(src, trim_characters, converter::trim_left);
}

void str::trim_right(string &src, const string &trim_characters) {
  converter::trim(src, trim_characters, converter::trim_right);
}

void str::left(string &src, unsigned int count) {
  if (count < src.length())
    src.erase(count);
}

void str::right(string &src, unsigned int count) {
  if (count < src.length())
    src.erase(0, src.length() - count);
}

void str::mid(string &src, unsigned int start_index, unsigned int count) {
  if (start_index < src.length()) {
    if ((start_index + count) < src.length())
      src.erase(start_index + count);

    src.erase(0, start_index);
  } else
    src.clear();
}

void str::split(const string &src, const string &pattern, list<string> &output) {
  const size_t pattern_length = pattern.length();
  output.resize(0);

  if (pattern_length != 0) {
    size_t index1 = 0;
    size_t index2 = src.find(pattern);

    while (index2 != string::npos) {
      if (index1 != index2) {
        output.push_back(global_empty_string);
        output.back().assign(src, index1, index2 - index1);
      } // if

      index1 = index2 + pattern_length;
      index2 = src.find(pattern, index1);
    } // while

    if (index1 < src.length()) { // makes sure that the last part will be inserted to the list
      output.push_back(global_empty_string);
      output.back().assign(src, index1, src.length() - index1);
    } // if

  } else
    output.push_back(src);
}

unsigned int str::count(const string &src, const string &search_string) {
  const size_t len = search_string.length();
  if (len == 0)
    return 0;

  size_t index = 0;
  unsigned int counter = 0;
  do {
    index = src.find(search_string, index);
    if (index == string::npos)
      break;

    index += len;
    ++counter;
  } while (true);

  return counter;
}

void str::to_upper(string &src) {
  string result;
  converter::to_upper(src, result);
  src = result;
}

void str::to_lower(string &src) {
  string result;
  converter::to_lower(src, result);
  src = result;
}

void str::prepend(string &src, char c, unsigned short total_length) {
  const size_t l = src.length();
  if (l >= total_length)
    return;

  src.insert(0, total_length - l, c);
}
